package utils;


import javax.swing.Box.Filler;
import javax.xml.parsers.*; 
import org.w3c.dom.*;
import org.xml.sax.*; 


import componentManager.Doc;
import componentManager.Noeud;
import componentManager.NoeudTerme;
import componentManager.Terme;

import java.io.*; 
import java.util.ArrayList;
import java.util.HashMap;


//TODO: ajout du nobre de termes dans chaque noeud et chaque document
public class Parser{
	
	public static final String DELIMITERS="[ ,;.?!:\t\r\n$%&@#()\\[\\]{}<>\"'_*+`��/\\\\-]";
	
	private static String stopListePath = "stopListe.txt";
	private ArrayList<String> stopList;
	
	private static DocumentBuilderFactory fabrique;
	private static DocumentBuilder constructeur;
	private static Document document;
	private ArrayList<Noeud> listNoeuds;
	private HashMap <String,Terme> listTermes;
	private ArrayList<Doc> lisDocuments;
	private ArrayList<NoeudTerme> listNoeudTerme;
	
	
	public Parser(){
		this.stopList = parseStopListFile();
		this.listNoeudTerme = new ArrayList<NoeudTerme>();
		this.lisDocuments = new ArrayList<Doc>();
		this.listNoeuds = new ArrayList<Noeud>();
		this.listTermes = new HashMap<String,Terme>();
		//Initialisation du parseur DOM
		try{
			// création d'une fabrique de documents
			fabrique = DocumentBuilderFactory.newInstance();
			// création d'un constructeur de documents
			constructeur = fabrique.newDocumentBuilder();
		}catch(ParserConfigurationException pce){
			System.out.println("Erreur de configuration du parseur DOM");
			System.out.println("lors de l'appel à fabrique.newDocumentBuilder();");
		}
	}
	
	public Parser(String collectionPath) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
		this();
		//Indexation des fichiers de la collection
		File[] list = GenerateId.findFileListOfDir(collectionPath,"^d[0-9]+\\.xml$");
		
		for ( File f : list ){
			indexADocument(f);
//			break;
	   }
	}
	
	/**
	 * Retourne la liste des fichiers d'un dossier
	 * @param dirPath
	 * @return
	 */
	public static File[] findFileListOfDir(String dirPath, String regexp){
		File dir = new File(dirPath);   
		File[] list=dir.listFiles(new FilenameFilter () {
		    @Override
		    public boolean accept (File dir, String name) {
		     return name.matches("^d[0-9]+\\.xml$");
		    }
		   });
		return list;
	}
	
	/**
	 * cherche le noeud parent (de type Noeud) dans dans la liste de noeud specifie
	 * chaque noeud �tant associ� un �l�ment de type Node
	 * @param n
	 * @param nodeList
	 * @return le noeud parent du noeud recherch�
	 */
	public Noeud findNoeudEquivalent(Node n, ArrayList<Noeud> nodeList){
		Noeud result=null;
		for(Noeud noeud : nodeList){
			if(noeud.getNoeud().equals(n)){
				result = noeud;
				break;
			}
		}
		return result;
	}
	/**
	 * Parcours les noeuds d'un document XML en partant du noeud racine
	 * puis stocke la liste des noeuds parcourus
	 * @param n
	 * @param nodeList : liste de noeud initial
	 * @return une liste de noeud
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 * @throws ClassNotFoundException 
	 */
	public ArrayList<Noeud> visitDocumentNodes(Node n, ArrayList<Noeud> nodeList,int idDoc) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
		ArrayList<Noeud> result = new ArrayList<Noeud>(); 
		int num = 1;
		for(int i=0;i<n.getChildNodes().getLength();i++){
			Node temp = n.getChildNodes().item(i);
			Noeud noeud = new Noeud();
			Noeud noeudparent = findNoeudEquivalent(temp.getParentNode(),nodeList);
			if(temp.getNodeType()!=Node.TEXT_NODE){
				noeud.setId(GenerateId.generateIdNoeud());
				noeud.setIdDoc(idDoc);
				//trouver le noeud parent correspondant au Nodeparent
				noeud.setIdNoeudpere(noeudparent.getId());
				noeud.setPath(noeudparent.getPath()+String.valueOf(num)+"-");
				num++;
				//a simplifier
				noeud.setLabel(noeudparent.getNoeud().getChildNodes().item(i).getNodeName());
				noeud.setNoeud(temp);
				//ajouter element à la BDD
				this.listNoeuds.add(noeud);
				result.add(noeud);	
			}else{//we are in a text contain
				String texte = temp.getTextContent().trim();
				if(texte.compareTo("")!=0){
					String[] tabTermes = texte.split(DELIMITERS);
					//on parcours la liste des termes
					for(int j=0;j<tabTermes.length;j++){
						if(!this.stopList.contains(tabTermes[j])&& tabTermes[j].trim().compareTo("")!=0){
							//s'il s'agit d'un nouveau terme
							Terme t = new Terme(tabTermes[j].trim());
							if(!this.listTermes.containsKey(t.getRadical())){
								t.setId(GenerateId.generateIdTerme());
								noeudparent.incrementNbreTerme();
								this.listTermes.put(t.getRadical(),t);
							}
							this.listNoeudTerme.add(new NoeudTerme(noeudparent.getId(),listTermes.get(t.getRadical()).getId(),j));
						}
					}
				}
			}
			
			result.addAll(visitDocumentNodes(temp,result,idDoc));
		}
		return result;
	}
	
	
	public static ArrayList<String> parseStopListFile(){
		ArrayList<String> result = new ArrayList<String>();
		File fichier = new File(Parser.stopListePath);
		//lecture du fichier texte	
		try{
			InputStream ips=new FileInputStream(fichier); 
			InputStreamReader ipsr=new InputStreamReader(ips);
			BufferedReader br=new BufferedReader(ipsr);
			String ligne;
			while ((ligne=br.readLine())!=null){
				result.add(ligne);
			}
			br.close(); 
		}		
		catch (Exception e){
			System.out.println(e.toString());
		}
		return result;
	}

	public void indexADocument(File xmlFile) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
		Doc doc =  new Doc(GenerateId.generateIdDoc());
		doc.setNomDoc(xmlFile.getName());
	 //   System.out.println("Nom de doc: "+xmlFile.getName());
		this.lisDocuments.add(doc);
		try{
			// lecture du contenu d'un fichier XML avec DOM
	
			//InputSource source = new InputSource(new FileInputStream(xmlFile));
			//source.setEncoding("utf-8");
			//source.setEncoding("iso-8859-1");
			//document = constructeur.parse(source);
			document = constructeur.parse(xmlFile);
			
			Element racine = document.getDocumentElement();
			Noeud noeud = new Noeud();
			noeud.setId(GenerateId.generateIdNoeud());
			noeud.setLabel(racine.getNodeName());
			noeud.setNoeud(racine);
			noeud.setIdNoeudpere(0);
			noeud.setIdDoc(doc.getId());
			noeud.setPath("1-");
			this.listNoeuds.add(noeud);
			ArrayList<Noeud> l = new ArrayList<Noeud>();
			l.add(noeud);
			ArrayList<Noeud> la = visitDocumentNodes(racine,l,doc.getId());
			
			//calcul du nombre de terme d'un document
			int somme = 0;
			for(Noeud n : la){
				somme+=n.getNbreTerme();
			}
			doc.setNbreTermes(somme);
//			displayAllNodes();
//			displayAllDoc();
//			displayAllTermes();
			
		}catch(SAXException se){
			System.out.println("Erreur lors du parsing du document");
			System.out.println("lors de l'appel à construteur.parse(xml)");
		}catch(IOException ioe){
			System.out.println("Erreur d'entrée/sortie");
			System.out.println("lors de l'appel à construteur.parse(xml)");
		}
	}
	
	public void displayAllNodes(){
		for(Noeud n : this.listNoeuds){
			if(n!=null)
				System.out.println(n);
		}
	}
	public void displayAllTermes(){
		for(String n : this.listTermes.keySet()){
			if(n!=null)
				System.out.println(this.listTermes.get(n));
		}
	}
	public void displayAllDoc(){
		for(Doc d: this.lisDocuments){
			System.out.println(d);
		}
	}
	

	
	
	
	
	
	
	public ArrayList<Noeud> getListNoeuds() {
		return listNoeuds;
	}

	public void setListNoeuds(ArrayList<Noeud> listNoeuds) {
		this.listNoeuds = listNoeuds;
	}

	public HashMap<String, Terme> getListTermes() {
		return listTermes;
	}

	public void setListTermes(HashMap<String, Terme> listTermes) {
		this.listTermes = listTermes;
	}

	public ArrayList<Doc> getLisDocuments() {
		return lisDocuments;
	}

	
	public static DocumentBuilder getConstructeur() {
		return constructeur;
	}

	public static void setConstructeur(DocumentBuilder constructeur) {
		Parser.constructeur = constructeur;
	}

	public static Document getDocument() {
		return document;
	}

	public static void setDocument(Document document) {
		Parser.document = document;
	}

	public ArrayList<NoeudTerme> getListNoeudTerme() {
		return listNoeudTerme;
	}

	public void setListNoeudTerme(ArrayList<NoeudTerme> listNoeudTerme) {
		this.listNoeudTerme = listNoeudTerme;
	}

	public void setLisDocuments(ArrayList<Doc> lisDocuments) {
		this.lisDocuments = lisDocuments;
	}

	

	public void fillBDD(){
		BDD.getInstance();
		System.out.println("D�but indexage");
		long l = System.currentTimeMillis();
		BDD.ajouterTousLesDocument(this.getLisDocuments());
		BDD.ajouterTousLesNoeud(this.getListNoeuds());
		
		ArrayList<Terme> a = new ArrayList<Terme>();
		a.addAll(this.getListTermes().values());
		BDD.ajouterTousLesTerme(a);
		
		int diviseur = 100;
		int deb=0;
		int fin=this.getListNoeudTerme().size()/diviseur;
		for(int i=0;i<diviseur;i++){
			ArrayList<NoeudTerme> b = new ArrayList<NoeudTerme>();
			b.addAll(this.getListNoeudTerme().subList(deb,fin));
			BDD.ajouterTousLesElementTerme(b);
			deb=fin;
			fin+=this.getListNoeudTerme().size()/diviseur;
		}
		
		l=(System.currentTimeMillis()-l)/1000;
		System.out.println("Fin indexage : "+l+"secondes");
		
	}
	
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
		
		Parser p = new Parser("Collection");
		p.fillBDD();
		
		
//		Node n = getCorrespondantNode("d001.xml","1-2-1-1-");
//		System.out.println(n.getNodeName());
		
	}
}
